package com.example.redis.controller;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author chensixiang chensixiang1234@gmail.com
 */
@RestController
@RequestMapping("/redis")
public class IndexController {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @GetMapping
    public String test() {
        redisTemplate.opsForValue().set("name", "chris");
        return (String) redisTemplate.opsForValue().get("name");
    }

    @GetMapping("lock")
    public void testLock() {
        String lockName = UUID.randomUUID().toString();
        // 上锁，并设置过期时间，为了防止锁的勿释放需要一个唯一id
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", lockName, 3, TimeUnit.SECONDS);
        if (lock != null && lock) {
            Object value = redisTemplate.opsForValue().get("num");
            if (!ObjectUtils.isEmpty(value)) {
                int num = Integer.parseInt(value + "");
                redisTemplate.opsForValue().set("num", ++num);
            }
            String redisLockName = (String) redisTemplate.opsForValue().get("lock");

            if (redisLockName != null && redisLockName.equals(lockName)) {
                // 会有问题
                // redisTemplate.delete("lock");
                String script = "if redis.call('get', KEY[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                redisScript.setResultType(Long.class);
                redisScript.setScriptText(script);
                redisTemplate.execute(redisScript, Collections.singletonList("lock"), lockName);
            }
        } else {
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                testLock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
